package xyz.apiote.stuff

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import xyz.apiote.stuff.databinding.ActivityContainerBinding
import android.content.Context
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.LinearLayoutManager
import android.app.Activity
import android.graphics.Rect
import android.view.*
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
import android.view.MotionEvent

// todo consts

class ContainerActivity : AppCompatActivity(), StuffAdapter.ItemClickListener {

	private lateinit var binding: ActivityContainerBinding
	private lateinit var stuff: Stuff
	private var mode: String = ""
	private lateinit var db: DB
	private lateinit var adapter: StuffAdapter
	private lateinit var containedStuff: ArrayList<Stuff>

	enum class REQUEST(val value: Int) {
		EDIT(0),
		PICK(1)
	}

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)

		db = DB(this)
		db.migrate()

		binding = ActivityContainerBinding.inflate(layoutInflater)
		setContentView(binding.root)

		mode = intent.extras?.get("mode") as String? ?: "view"
		stuff = db.loadStuff(intent.extras?.get("ID") as Long? ?: 0)

		setSupportActionBar(binding.toolbar)
		supportActionBar!!.title = stuff.name

		if (mode == "pick") {
			setResult(RESULT_CANCELED)
			binding.fab.visibility = View.GONE
		} else {
			binding.fab.setOnClickListener {
				val editIntent = Intent(this, EditActivity::class.java)
				editIntent.putExtra("container", stuff.id)
				startActivityForResult(editIntent, REQUEST.EDIT.value)
			}
		}

		binding.stuffRecycler.layoutManager = LinearLayoutManager(this)
		adapter = StuffAdapter(this, emptyList())
		adapter.setClickListener(this)
		binding.stuffRecycler.adapter = adapter
	}

	override fun onResume() {
		super.onResume()
		updateStuffList()
		swapListVisibility()
		hideBottom()
	}

	@SuppressLint("NotifyDataSetChanged")
	private fun updateStuffList(notify: Boolean = true) {
		containedStuff = db.loadContainer(stuff.id!!)
		adapter.setData(containedStuff)
		if (notify) {
			// todo calculate changes (probably only inserts, we cannot delete if we’re not there)
			adapter.notifyDataSetChanged()
		}
	}

	private fun swapListVisibility() {
		if (containedStuff.isEmpty()) {
			binding.emptyState.root.visibility = View.VISIBLE
			binding.stuffRecycler.visibility = View.GONE
		} else {
			binding.emptyState.root.visibility = View.GONE
			binding.stuffRecycler.visibility = View.VISIBLE
		}
	}

	override fun onItemClick(view: View?, position: Int) {
		val selectedStuff = adapter.getItem(position)
		val selectedContents = db.loadContainer(selectedStuff.id!!)
		when {
			mode == "pick" -> {
				val pickIntent = Intent(this, ContainerActivity::class.java)
				pickIntent.putExtra("mode", "pick")
				pickIntent.putExtra("ID", selectedStuff.id)
				startActivityForResult(pickIntent, REQUEST.PICK.value)
			}
			selectedContents.isNotEmpty() -> {
				val viewIntent = Intent(this, ContainerActivity::class.java)
				viewIntent.putExtra("ID", selectedStuff.id)
				startActivity(viewIntent)
			}
			else -> {
				showBottomInfo(selectedStuff)
			}
		}
	}

	private fun hideBottom() {
		val bottomSheet = findViewById<ConstraintLayout>(R.id.standard_bottom_sheet)
		val bottomSheetBehavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet)
		bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
	}

	private fun showBottomInfo(selectedStuff: Stuff) {
		val bottomSheetBehavior = BottomSheetBehavior.from(binding.standardBottomSheet)
		bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
		binding.bottomStuffName.text = selectedStuff.name
		binding.bottomStuffDescription.text = selectedStuff.description
		binding.bottomEdit.setOnClickListener {
			hideBottom()
			val editIntent = Intent(this, EditActivity::class.java)
			editIntent.putExtra("ID", selectedStuff.id)
			startActivityForResult(editIntent, REQUEST.EDIT.value)
		}

		if (selectedStuff.id == 0L) {
			binding.bottomDelete.visibility = View.GONE
			binding.bottomEdit.visibility = View.GONE
		} else {
			binding.bottomDelete.visibility = View.VISIBLE
			binding.bottomEdit.visibility = View.VISIBLE
			binding.bottomDelete.setOnClickListener {
				if (db.loadContainer(selectedStuff.id!!).isNotEmpty()) {
					Snackbar.make(
						binding.root,
						getString(R.string.stuff_not_empty, selectedStuff.name),
						Snackbar.LENGTH_SHORT
					)
						.show()
				} else {
					db.deleteStuff(selectedStuff.id)
					val position = adapter.getPosition(selectedStuff.id)
					containedStuff = db.loadContainer(stuff.id!!)
					adapter.setData(containedStuff)
					adapter.notifyItemRemoved(position)
					hideBottom()
					swapListVisibility()
				}
			}
		}
	}

	override fun onCreateOptionsMenu(menu: Menu): Boolean {
		if (mode == "view") {
			if (stuff.id != 0L) {
				menuInflater.inflate(R.menu.menu_container_view, menu)
			} else {
				menuInflater.inflate(R.menu.menu_container_view_ie, menu)
			}
		} else if (mode == "pick") {
			menuInflater.inflate(R.menu.menu_container_pick, menu)
		}
		return true
	}

	override fun onOptionsItemSelected(item: MenuItem): Boolean {
		return when (item.itemId) {
			R.id.action_info -> {
				showBottomInfo(stuff)
				true
			}
			R.id.action_import_export -> {
				val intent = Intent(this, ImportExportActivity::class.java)
				startActivity(intent)
				true
			}
			R.id.action_pick -> {
				val returnIntent = Intent()
				returnIntent.putExtra("stuffID", stuff.id)
				setResult(RESULT_OK, returnIntent)
				finish()
				true
			}
			else -> super.onOptionsItemSelected(item)
		}
	}

	override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
		val bottomSheetBehavior = BottomSheetBehavior.from(binding.standardBottomSheet)
		if (event?.action == MotionEvent.ACTION_DOWN) {
			val outRect = Rect()
			binding.standardBottomSheet.getGlobalVisibleRect(outRect)
			if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
				bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
			}
		}

		return super.dispatchTouchEvent(event)
	}

	// fixme https://proandroiddev.com/is-onactivityresult-deprecated-in-activity-results-api-lets-deep-dive-into-it-302d5cf6edd?gi=75b767b0d7ea
	override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
		super.onActivityResult(requestCode, resultCode, data)
		if (requestCode == REQUEST.PICK.value && resultCode == Activity.RESULT_OK) {
			val stuffID = data!!.getLongExtra("stuffID", -1L)
			val returnIntent = Intent()
			returnIntent.putExtra("stuffID", stuffID)
			setResult(RESULT_OK, returnIntent)
			finish()
		}
		if (requestCode == REQUEST.EDIT.value && resultCode == Activity.RESULT_OK) {
			val newStuffID = data!!.getLongExtra("stuffID", -1L)
			val isInserted = data.getBooleanExtra("inserted", false)
			val newContainer = data.getLongExtra("newContainer", -1L)
			if (isInserted && newContainer == stuff.container) {
				updateStuffList(false)
				swapListVisibility()
				val position = adapter.getPosition(newStuffID)
				adapter.notifyItemInserted(position)
			}
			if (!isInserted) {
				if (!adapter.contains(newStuffID)) {
					// fixme if newContainer != -1 -> up is incorrect
					supportActionBar!!.title = db.loadStuff(newStuffID).name
				} else {
					val position = adapter.getPosition(newStuffID)
					updateStuffList(false)
					if (newContainer == -1L) {
						adapter.notifyItemChanged(position)
					} else {
						adapter.notifyItemRemoved(position)
						swapListVisibility()
					}
				}
			}
		}
	}
}

class StuffAdapter internal constructor(context: Context?, private var data: List<Stuff>) :
	RecyclerView.Adapter<StuffAdapter.ViewHolder>() {
	private val inflater = LayoutInflater.from(context)
	private var clickListener: ItemClickListener? = null

	inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView),
		View.OnClickListener {
		var stuffNameTextView = itemView.findViewById<TextView>(R.id.rowStuffName)!!
		override fun onClick(view: View) {
			clickListener?.onItemClick(view, adapterPosition)
		}

		init {
			itemView.setOnClickListener(this)
		}
	}

	override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
		val view: View = inflater.inflate(R.layout.stuff_row, parent, false)
		return ViewHolder(view)
	}

	override fun onBindViewHolder(holder: ViewHolder, position: Int) {
		holder.stuffNameTextView.text = data[position].name
	}

	override fun getItemCount(): Int {
		return data.size
	}

	fun setData(newData: List<Stuff>) {
		data = newData
	}

	fun getItem(position: Int): Stuff {
		return data[position]
	}

	fun getPosition(id: Long): Int {
		return data.indexOfFirst {
			it.id == id
		}
	}

	fun contains(id: Long): Boolean {
		return getPosition(id) != -1
	}

	fun setClickListener(itemClickListener: ItemClickListener?) {
		clickListener = itemClickListener
	}

	interface ItemClickListener {
		fun onItemClick(view: View?, position: Int)
	}
}